package com.chen.holiday.app.holiday;

import com.chen.holiday.client.api.HolidayServiceI;
import com.chen.holiday.domain.holiday.Holiday;
import com.chen.holiday.domain.holiday.HolidayGateWay;
import com.chen.holiday.infrastructure.holiday.HolidayGateWayImpl;


import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * @author 陈浩
 * @date 2021/5/19 8:25
 */
public class HolidayServiceImpl implements HolidayServiceI {

    private final HolidayGateWay gateWay = new HolidayGateWayImpl();

    public HolidayServiceImpl() throws Exception {
    }

    @Override
    public boolean isHoliday(LocalDate date) {
        Holiday holiday = gateWay.getDay(date);
        if (holiday != null) {
            return holiday.getHoliday();
        }

        return gateWay.isWeekend(date);
    }

    @Override
    public LocalDate getNextWorkDay() {
        Holiday holiday = gateWay.getToday();
        return countNextWorkDay(holiday, LocalDate.now());
    }

    @Override
    public LocalDate getNextWorkDay(LocalDate date) {
        Holiday holiday = gateWay.getDay(date);
        return countNextWorkDay(holiday, date);
    }

    @Override
    public LocalDateTime getNextWorkDay(LocalDateTime date) {
        // 需求是周五下午12点后，当做周末一样;
        if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY) && date.getHour() >= 12) {
            date = date.plusDays(1);
        }
        Holiday holiday = gateWay.getDay(date);
        return countNextWorkDay(holiday, date);
    }

    private LocalDate weekendCount(LocalDate date) {
        if (date.getDayOfWeek().equals(DayOfWeek.SUNDAY)) {
            return date.plusDays(1);
        } else {
            return date.plusDays(2);
        }
    }

    private LocalDateTime weekendCount(LocalDateTime date) {
        if (date.getDayOfWeek().equals(DayOfWeek.SUNDAY)) {
            return date.plusDays(1).withHour(12).withMinute(0).withSecond(0).withNano(0);
        } else {
            return date.plusDays(2).withHour(12).withMinute(0).withSecond(0).withNano(0);
        }
    }

    private LocalDate countNextWorkDay(Holiday holiday, LocalDate date) {
        // 是不是节假日或者补班
        if (holiday != null) {
            // 补班直接返回当天
            if (holiday.getHoliday().equals(false)) {
                return date;
            } else {
                // 返回节假日结束的第一天
                int size = holiday.getNextDay().size();
                return holiday.getDate().plusDays(size + 1);
            }
        }

        // 不是节假日，是否为周末
        boolean weekend = gateWay.isWeekend(date);
        // 是周末就去就按周末的去算
        if (weekend) {
            return weekendCount(date);
        }

        return date;
    }

    /**
     * 先判断是不是法定节假日和周末
     * @param holiday
     * @param date
     * @return
     */
    private LocalDateTime countNextWorkDay(Holiday holiday, LocalDateTime date) {
        int h = date.getHour();
        if (holiday != null) {
            // 补班
            if (holiday.getHoliday().equals(false)) {
                // 如果是补周六的，并且已经是下午了，就返回星期一12点
                if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY) && date.getHour() >= 12) {
                    return date.plusDays(2).withHour(12).withMinute(0).withSecond(0).withNano(0);
                } else {
                    // 如果是补周日的，上午的单就放回当天18点，下午的单就返回星期一12点
                    return h >= 12 ? date.plusDays(1).withHour(12).withMinute(0).withSecond(0).withNano(0) : date.withHour(18).withMinute(0).withSecond(0).withNano(0);
                }
            } else {
                // 节假日
                int size = holiday.getNextDay().size();
                LocalDate holidayDate = holiday.getDate();
                return LocalDateTime.of(holidayDate, LocalTime.of(12, 0)).plusDays(size + 1);
            }
        }

        // 不是节假日和补班的，判断是否周末
        boolean weekend = gateWay.isWeekend(date.toLocalDate());
        if (weekend) {
            return weekendCount(date);
        }

        // 正常工作日，上午的单就放回当天18点，下午的单就返回第二天12点
        return h >= 12 ? date.plusDays(1).withHour(12).withMinute(0).withSecond(0).withNano(0) : date.withHour(18).withMinute(0).withSecond(0).withNano(0);
    }

}
